#include <iostream>
#include <iomanip>
#include "conio.h"
#include "actualizador.h"
#include "utiles.h"
#include "formas.h"
#include "juego.h"
using namespace std;

bool actualizarMenu(bool** tablero, int ancho, int alto)
{
	cout << "Seleccine una opcion: ";
	char opcion = toupper(getch());
	switch (opcion)
	{
		case 'Z':	// Glider
			agregarFormaATablero(
				GLIDER,
				CELULAS_GLIDER,
				tablero,
				ancho,
				alto
			);
			jugar(tablero, ancho, alto);
			break;
		case 'X':	// Pulsar
			agregarFormaATablero(
				PULSAR,
				CELULAS_PULSAR,
				tablero,
				ancho,
				alto
			);
			jugar(tablero, ancho, alto);
			break;
		case 'C':	// Pentadecatlon
			agregarFormaATablero(
				PENTADECATLON,
				CELULAS_PENTADECATLON,
				tablero,
				ancho,
				alto
			);
			jugar(tablero, ancho, alto);
			break;
		case 'S':	// Salir
			return true;
		default:	// Error
			cout << "ERROR!" << endl;
			break;
	}
	return false;
}

bool actualizarJuego(bool** tablero, int ancho, int alto)
{
	cout << "Seleccine una opcion: ";
	char opcion = toupper(getch());
	switch (opcion)
	{
		case 'N':	// Siguiente iteracion
			iterar(tablero, ancho, alto);
			break;
		case 'V':	// Volver (al menu principal)
			return true;
		default:		// Error
			cout << "ERROR!" << endl;
			break;
	}
	return false;
}

// agrego forma predefinida al tablero
void agregarFormaATablero(
	const Punto** forma,
	int cantidadDeCelulas,
	bool** tablero,
	int ancho,
	int alto
)
{
	Punto* pInicial = new Punto(int(ancho/2), int(alto/2));
	Punto* pTemporal = new Punto();

	limpiarMatrizBool2D(tablero, ancho, alto);

	for (int i = 0; i < cantidadDeCelulas; i++)
	{
		pTemporal = &(pInicial->sumar(forma[i]->X(), forma[i]->Y()));
		tablero[pTemporal->X()][pTemporal->Y()] = true;
	}
	
	delete pInicial;
	delete pTemporal;
}

// tomo el estado actual de la matriz y le aplico las reglas del juego
void iterar(bool** tablero, int ancho, int alto)
{
	bool** copia = copiarMatrizBool2D(tablero, ancho, alto);
	
	for (int i = 0; i < ancho; i++)
	{
		for (int j = 0; j < alto; j++)
		{
			int vecinos = calcularVecinos(copia, ancho, alto, i, j);
			if (tablero[i][j])
				tablero[i][j] = (vecinos == 2 || vecinos == 3);
			else
				tablero[i][j] = vecinos == 3;
		}
	}
	delete copia;
}

int calcularVecinos(bool** tablero, int ancho, int alto, int i, int j)
{
	Punto** direcciones = new Punto*[8];
	direcciones[0] = new Punto(dentroDeRango(i-1, 0, ancho-1), dentroDeRango(j-1, 0, alto-1));
	direcciones[1] = new Punto(dentroDeRango(i, 0, ancho-1), dentroDeRango(j-1, 0, alto-1));
	direcciones[2] = new Punto(dentroDeRango(i+1, 0, ancho-1), dentroDeRango(j-1, 0, alto-1));
	direcciones[3] = new Punto(dentroDeRango(i-1, 0, ancho-1), dentroDeRango(j, 0, alto-1));
	direcciones[4] = new Punto(dentroDeRango(i+1, 0, ancho-1), dentroDeRango(j, 0, alto-1));
	direcciones[5] = new Punto(dentroDeRango(i+1, 0, ancho-1), dentroDeRango(j+1, 0, alto-1));
	direcciones[6] = new Punto(dentroDeRango(i, 0, ancho-1), dentroDeRango(j+1, 0, alto-1));
	direcciones[7] = new Punto(dentroDeRango(i-1, 0, ancho-1), dentroDeRango(j+1, 0, alto-1));
	
	int vecinos = 0;
	for (int l = 0; l < 8; l++) {
		if (tablero[direcciones[l]->X()][direcciones[l]->Y()]) vecinos++;
		delete direcciones[l];
	}
	delete direcciones;
	return vecinos;
}

int dentroDeRango(int a, int minimo, int maximo)
{
	if (a < minimo)
		return maximo;
	if (a > maximo)
		return minimo;
	return a;
}
